#include "stack_chat_db.h"

stack_chat_db::stack_chat_db()
{
	std::string configFilePath = "./config/mysql_config.json";
	driver = get_driver_instance();
	Json::Value root;
	Json::Reader reader;

	std::ifstream configFile(configFilePath, std::ifstream::binary);
	bool parsingSuccessful = reader.parse(configFile, root);
	configFile.close();

	if (!parsingSuccessful) {
		std::cerr << "Failed to parse configuration file(mysql)\n\a" << std::endl;
		exit(-1);
	}

	std::string ip = root["ip"].asString();
	std::string port = root["port"].asString();
	std::string dba = root["dba"].asString();
	std::string password = root["password"].asString();
	std::string schema = root["schema"].asString();

	driver = get_driver_instance();
	con = driver->connect("tcp://" + ip + ":" + port, dba, password);
	con->setSchema(schema);
}
stack_chat_db::~stack_chat_db()
{
	delete con;
}

void stack_chat_db::printDriverInfo()
{
	std::cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl;
	std::cout << "| driver name : " << driver->getName() << " |" << std::endl;
	std::cout << "| driver version : " << driver->getMajorVersion() << "."
		<< driver->getMinorVersion() << "."
		<< driver->getPatchVersion() << "\t\t       |" << std::endl;
	std::cout << "------------------------------------------------" << std::endl;
}

void stack_chat_db::printConnectInfo()
{
	std::cout << "++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl;
	std::cout << "| client info : " << con->getClientInfo() << "\t\t\t       |" << std::endl;
	std::cout << "| current database : " << con->getSchema() << "\t\t       |" << std::endl;
	std::cout << "------------------------------------------------" << std::endl;
}
int stack_chat_db::userSearchByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM user WHERE user_id = " + std::to_string(id));
	if (res->next())
	{
		delete res;
		delete stmt;
		return 1;
	}
	else
	{
		delete res;
		delete stmt;
		return 0;
	}
}

std::string stack_chat_db::userGetNameByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM user WHERE user_id = " + std::to_string(id));
	if (res->next())
	{
		auto tmp = res->getString("user_name");
		delete res;
		delete stmt;
		return tmp;
	}
	else
	{
		delete res;
		delete stmt;
		return "";
	}
}

std::string stack_chat_db::userGetPasswordByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM user WHERE user_id = " + std::to_string(id));
	if (res->next())
	{
		auto tmp = res->getString("user_password");
		delete res;
		delete stmt;
		return tmp;
	}
	else
	{
		delete res;
		delete stmt;
		return "";
	}
}

int stack_chat_db::userUpdateNameByID(const int& id, const std::string& name)
{
	if (userSearchByID(id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("UPDATE user SET user_name = ? WHERE user_id = ?");
		prep_stmt->setString(1, name);
		prep_stmt->setInt(2, id);
		prep_stmt->execute();
		return 1;
	}
}

int stack_chat_db::userUpdatePasswordByID(const int& id, const std::string& password)
{
	if (userSearchByID(id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("UPDATE user SET user_password = ? WHERE user_id = ?");
		prep_stmt->setString(1, password);
		prep_stmt->setInt(2, id);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}

int stack_chat_db::userDeleteByID(const int& id)
{
	if (userSearchByID(id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("DELETE FROM user WHERE user_id = ?");
		prep_stmt->setInt(1, id);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}

int stack_chat_db::userInsert(const int& id, const std::string& name, const std::string& password)
{
	if (userSearchByID(id) == 1)
	{
		return 3;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("INSERT INTO user VALUES(?,?,?)");
		prep_stmt->setInt(1, id);
		prep_stmt->setString(2, name);
		prep_stmt->setString(3, password);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}

int stack_chat_db::user_infoSearchByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM user_info WHERE user_info_id = " + std::to_string(id));
	if (res->next())
	{
		delete res;
		delete stmt;
		return 1;
	}
	else
	{
		delete res;
		delete stmt;
		return 0;
	}
}
int stack_chat_db::user_infoInsert(const user_info& uf)
{
	if (user_infoSearchByID(uf.id) == 1 || userSearchByID(uf.id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("INSERT INTO user_info VALUES(?,?,?,?,?,?,?)");
		prep_stmt->setInt(1, uf.id);
		prep_stmt->setString(2, uf.sex);
		prep_stmt->setString(3, uf.info);
		prep_stmt->setString(4, uf.email);
		prep_stmt->setString(5, uf.phone);
		prep_stmt->setInt(6, uf.age);
		prep_stmt->setString(7, uf.gtime);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::user_infoDeleteByID(const int& id)
{
	if (user_infoSearchByID(id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("DELETE FROM user_info WHERE user_info_id = ?");
		prep_stmt->setInt(1, id);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::user_infoUpdateByID(const user_info& uf)
{
	if (user_infoSearchByID(uf.id) == 0)
	{
		return 0;
	}
	else
	{
		user_infoDeleteByID(uf.id);
		user_infoInsert(uf);
		return 1;
	}
}
stack_chat_db::user_info stack_chat_db::user_infoGetInfoByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM user_info WHERE user_info_id = " + std::to_string(id));
	if (res->next())
	{
		user_info tmp;
		tmp.id = id;
		tmp.age = res->getInt("user_age");
		tmp.email = res->getString("user_email");
		tmp.gtime = res->getString("user_gtime");
		tmp.info = res->getString("user_info");
		tmp.phone = res->getString("user_phone");
		tmp.sex = res->getString("user_sex");
		delete res;
		delete stmt;
		return tmp;
	}
	else
	{
		delete res;
		delete stmt;
		return user_info();
	}
}
int stack_chat_db::server_logSearchByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM server_log WHERE server_log_id = " + std::to_string(id));
	if (res->next())
	{
		delete res;
		delete stmt;
		return 1;
	}
	else
	{
		delete res;
		delete stmt;
		return 0;
	}
}
int stack_chat_db::server_logInsert(const server_log& sl)
{
	if (server_logSearchByID(sl.id) == 1)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("INSERT INTO server_log VALUES(?,?,?,?)");
		prep_stmt->setInt(1, sl.id);
		prep_stmt->setString(2, sl.data);
		prep_stmt->setString(3, sl.time);
		prep_stmt->setInt(4, sl.level);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::server_logDeleteByID(const int& id)
{
	if (server_logSearchByID(id) == 0)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("DELETE FROM server_log WHERE server_log_id = ?");
		prep_stmt->setInt(1, id);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::server_logUpdateByID(const server_log& sl)
{
	if (server_logSearchByID(sl.id) == 0)
	{
		return 0;
	}
	else
	{
		server_logDeleteByID(sl.id);
		server_logInsert(sl);
		return 1;
	}
}
stack_chat_db::server_log stack_chat_db::server_logGetLogByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM server_log WHERE server_log_id = " + std::to_string(id));
	if (res->next())
	{
		server_log tmp;
		tmp.id = id;
		tmp.data = res->getString("server_log_data");
		tmp.time = res->getString("server_log_time");
		tmp.level = res->getInt("server_log_level");
		delete res;
		delete stmt;
		return tmp;
	}
	else
	{
		delete res;
		delete stmt;
		return server_log();
	}
}
int stack_chat_db::message_logSearchByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM message_log WHERE msg_id = " + std::to_string(id));
	if (res->next())
	{
		delete res;
		delete stmt;
		return 1;
	}
	else
	{
		delete res;
		delete stmt;
		return 0;
	}
}
std::string stack_chat_db::message_logGetMessageByUserID(const int& id)
{
	if (userSearchByID(id) == 0)
	{
		return Json::Value().toStyledString();
	}
	else
	{
		Json::Value root;
		Json::Value msgList(Json::arrayValue);
		sql::Statement* stmt = con->createStatement();
		sql::ResultSet* res = stmt->executeQuery("SELECT * FROM message_log WHERE msg_send_id = " + std::to_string(id) + " OR msg_receive_id = " + std::to_string(id));
		while (res->next())
		{
			message_log msg;
			msg.id = res->getInt("msg_id");
			msg.send_id = res->getInt("msg_send_id");
			msg.receive_id = res->getInt("msg_receive_id");
			msg.status = res->getInt("msg_status");
			msg.data = res->getString("msg_data");
			msg.time = res->getString("msg_time");

			Json::Value msgJson;
			msgJson["msg_id"] = msg.id;
			msgJson["msg_send_id"] = msg.send_id;
			msgJson["msg_receive_id"] = msg.receive_id;
			msgJson["msg_status"] = msg.status;
			msgJson["msg_data"] = msg.data;
			msgJson["msg_time"] = msg.time;
			//std::cout << msg.data << std::endl;

			msgList.append(msgJson);

		}
		root["all_message"] = msgList;
		//auto rt = root["all_message"];
		//for (int i = 0; i < rt.size(); i++)
		//{
		//	std::cout << rt[i]["msg_data"].asString() << std::endl;

		//}
		return root.toStyledString();
	}
}
int stack_chat_db::message_logInsert(const message_log& ml)
{
	if (userSearchByID(ml.receive_id) == 0 || userSearchByID(ml.send_id) == 0 || message_logSearchByID(ml.id) == 1)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement(
			"INSERT INTO message_log VALUES(?,?,?,?,?,?)");
		prep_stmt->setInt(1, ml.id);
		prep_stmt->setString(2, ml.data);
		prep_stmt->setString(3, ml.time);
		prep_stmt->setInt(4, ml.send_id);
		prep_stmt->setInt(5, ml.receive_id);
		prep_stmt->setInt(6, ml.status);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::friend_tableSearchByID(const int& id)
{
	sql::Statement* stmt = con->createStatement();
	sql::ResultSet* res = stmt->executeQuery("SELECT * FROM friend WHERE friend_id = " + std::to_string(id));
	if (res->next())
	{
		delete res;
		delete stmt;
		return 1;
	}
	else
	{
		delete res;
		delete stmt;
		return 0;
	}
}
std::string stack_chat_db::friend_tableGetFriendsByUserID(const int& id)
{
	if (userSearchByID(id) == 0)
	{
		return Json::Value().toStyledString();
	}
	else
	{
		Json::Value root;
		Json::Value frdList(Json::arrayValue);
		sql::Statement* stmt = con->createStatement();
		sql::ResultSet* res = stmt->executeQuery("SELECT * FROM friend WHERE user_id_a = " + std::to_string(id) + " OR user_id_b = " + std::to_string(id));
		while (res->next())
		{
			Json::Value frdJson;
			frdJson["friend_id"] = int(res->getInt("friend_id"));
			frdJson["user_id_a"] = int(res->getInt("user_id_a"));
			frdJson["user_id_b"] = int(res->getInt("user_id_b"));
			frdJson["friend_time"] = std::string(res->getString("friend_time"));

			frdList.append(frdJson);

		}
		root["all_friend"] = frdList;
		//auto rt = root["all_friend"];
		//for (int i = 0; i < rt.size(); i++)
		//{
		//	std::cout << rt[i]["friend_time"].asString() << std::endl;
		//}
		return root.toStyledString();
	}
}
int stack_chat_db::friend_tableIsFriend(const int& ida, const int& idb)
{
	if (userSearchByID(ida) == 0 || userSearchByID(idb) == 0)
	{
		return 0;
	}
	else
	{
		sql::Statement* stmt = con->createStatement();
		std::string query = "SELECT * FROM friend WHERE (user_id_a = " +
			std::to_string(ida) +
			" AND user_id_b = " +
			std::to_string(idb) +
			" ) OR ( user_id_b = " +
			std::to_string(ida) +
			" AND user_id_a = " +
			std::to_string(idb) +
			")";
		//std::cout << query << std::endl;
		sql::ResultSet* res = stmt->executeQuery(query);
		if (res->next())
		{
			int fid = res->getInt("friend_id");
			delete stmt;
			delete res;
			return fid;
		}
		else
		{
			delete stmt;
			delete res;
			return 0;
		}
	}
}
int stack_chat_db::friend_tableDeleteByUserID(const int& ida, const int& idb)
{
	int fid = friend_tableIsFriend(ida, idb);
	if (fid == 0)
	{
		return 0;
	}
	else
	{
		std::cout << fid << std::endl;
		sql::PreparedStatement* prep_stmt = con->prepareStatement("DELETE FROM friend WHERE friend_id = ?");
		prep_stmt->setInt(1, fid);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}
int stack_chat_db::friend_tableInsert(const friend_table& ft)
{
	if (friend_tableIsFriend(ft.user_id_a, ft.user_id_b) == 1 ||
		userSearchByID(ft.user_id_a) == 0 ||
		userSearchByID(ft.user_id_b) == 0 ||
		friend_tableSearchByID(ft.friend_id) == 1)
	{
		return 0;
	}
	else
	{
		sql::PreparedStatement* prep_stmt = con->prepareStatement("INSERT INTO friend VALUES(?,?,?,?)");
		prep_stmt->setInt(1, ft.friend_id);
		prep_stmt->setInt(2, ft.user_id_a);
		prep_stmt->setInt(3, ft.user_id_b);
		prep_stmt->setString(4, ft.friend_time);
		prep_stmt->execute();
		delete prep_stmt;
		return 1;
	}
}